package com.my.dao.impl;

import java.io.Serializable;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.my.dao.DAO;
import com.my.entity.BasicModel;

public class DAOImpl<T extends BasicModel> implements DAO<T> {
	
	private SessionFactory sessionFactory;

	public DAOImpl() {
		sessionFactory = new Configuration().configure().buildSessionFactory();
	}
	
	public Object execute(SessionCallback action) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		try {
			Object t = action.doInSession(session);
			session.getTransaction().commit();
			return t;
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}
		return null;
		
	}

	@Override
	public void create(final T t) {
		this.execute(new SessionCallback() {

			@Override
			public T doInSession(Session session) throws HibernateException {
				session.save(t);
				return null;
			}
			
		});
	}
	
	@Override
	public void update(final T t) {
		this.execute(new SessionCallback() {

			@Override
			public T doInSession(Session session) throws HibernateException {
				session.update(t);
				return t;
			}
			
		});
	}
	
	@Override
	public void delete(final T t) {
		this.execute(new SessionCallback() {

			@Override
			public T doInSession(Session session) throws HibernateException {
				session.delete(t);
				return t;
			}
			
		});
	}
	
	@Override
	public T get(final Class<T> t, final Serializable id) {
		return (T) this.execute(new SessionCallback() {

			@Override
			public T doInSession(Session session) throws HibernateException {
				T obj = (T) session.get(t, id);
				return obj;
			}
			
		});
	}
	
	@SuppressWarnings("rawtypes")
	@Override
	public List queryByHQL(final String hql, final Object... params) {
		return (List) this.execute(new SessionCallback() {

			@Override
			public List doInSession(Session session) throws HibernateException {
				Query q = session.createQuery(hql);
				int i = 0;
				for(Object param: params) {
					q.setParameter(i++, param);
				}
				return q.list();
			}
			
		});
	}
	
	@SuppressWarnings("rawtypes")
	@Override
	public Integer updateByHQL(final String hql, final Object... params) {
		return (Integer) this.execute(new SessionCallback() {

			@Override
			public Integer doInSession(Session session) throws HibernateException {
				Query q = session.createQuery(hql);
				int i = 0;
				for(Object param: params) {
					q.setParameter(i++, param);
				}
				return q.executeUpdate();
			}
			
		});
	}

	private interface SessionCallback {
		public Object doInSession(Session session) throws HibernateException;
	}
}
